//// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
//package com.linqingying.gitcode.pullrequest.ui.toolwindow.model
//
//
//import com.github.benmanes.caffeine.cache.Caffeine
//import com.intellij.collaboration.async.withInitial
//import com.intellij.collaboration.ui.toolwindow.ReviewToolwindowProjectViewModel
//import com.intellij.collaboration.ui.toolwindow.ReviewToolwindowTabs
//import com.intellij.collaboration.ui.toolwindow.ReviewToolwindowTabsStateHolder
//import com.intellij.collaboration.util.ComputedResult
//import com.intellij.collaboration.util.computeEmitting
//import com.intellij.collaboration.util.onFailure
//import com.intellij.openapi.Disposable
//import com.intellij.openapi.components.service
//import com.intellij.openapi.diagnostic.logger
//import com.intellij.openapi.project.Project
//import com.intellij.platform.util.coroutines.childScope
//import git4idea.GitStandardRemoteBranch
//import git4idea.push.GitPushRepoResult
//import git4idea.remote.hosting.findHostedRemoteBranchTrackedByCurrent
//import git4idea.remote.hosting.knownRepositories
//import kotlinx.coroutines.CoroutineScope
//import kotlinx.coroutines.channels.BufferOverflow
//import kotlinx.coroutines.flow.*
//import org.jetbrains.annotations.ApiStatus
//import com.linqingying.gitcode.api.GCRepositoryConnection
//import com.linqingying.gitcode.api.GCRepositoryCoordinates
//import com.linqingying.gitcode.api.data.pullrequest.GCPullRequestShort
//import com.linqingying.gitcode.pullrequest.GCPRListViewModel
//import com.linqingying.gitcode.pullrequest.data.GCPRDataContext
//import com.linqingying.gitcode.pullrequest.data.GCPRIdentifier
//import com.linqingying.gitcode.pullrequest.ui.GCPRViewModelContainer
//import com.linqingying.gitcode.pullrequest.ui.diff.GCPRDiffViewModel
//import com.linqingying.gitcode.pullrequest.ui.editor.GCPRReviewInEditorViewModel
//import com.linqingying.gitcode.pullrequest.ui.review.GCPRBranchWidgetViewModel
//import com.linqingying.gitcode.pullrequest.ui.timeline.GCPRTimelineViewModel
//import com.linqingying.gitcode.pullrequest.ui.toolwindow.GCPRToolWindowTab
//import com.linqingying.gitcode.ui.util.GCUIUtil
//import com.linqingying.gitcode.util.DisposalCountingHolder
//import com.linqingying.gitcode.util.GCGitRepositoryMapping
//import com.linqingying.gitcode.util.GCHostedRepositoriesManager
//
//private val LOG = logger<GCPRToolWindowProjectViewModel>()
//
//@ApiStatus.Experimental
//class GCPRToolWindowProjectViewModel internal constructor(
//  private val project: Project,
//  parentCs: CoroutineScope,
//  private val twVm: GCPRToolWindowViewModel,
//  connection: GCRepositoryConnection
//) : ReviewToolwindowProjectViewModel<GCPRToolWindowTab, GCPRToolWindowTabViewModel> {
//  private val cs = parentCs.childScope()
//
//  internal val dataContext: GCPRDataContext = connection.dataContext
//  val defaultBranch: String? = dataContext.repositoryDataService.defaultBranchName
//
//  private val repoManager = project.service<GCHostedRepositoriesManager>()
//  private val allRepos = repoManager.knownRepositories.map(GCGitRepositoryMapping::repository)
//  val repository: GCRepositoryCoordinates = dataContext.repositoryDataService.repositoryCoordinates
//  override val projectName: String = GCUIUtil.getRepositoryDisplayName(allRepos, repository)
//
//  override val listVm: GCPRListViewModel = GCPRListViewModel(project, cs, connection.dataContext)
//
//  private val pullRequestsVms = Caffeine.newBuilder().build<GCPRIdentifier, DisposalCountingHolder<GCPRViewModelContainer>> { id ->
//    DisposalCountingHolder {
//      GCPRViewModelContainer(project, cs, dataContext, this, id, it)
//    }
//  }
//
//  private val tabsHelper = ReviewToolwindowTabsStateHolder<GCPRToolWindowTab, GCPRToolWindowTabViewModel>()
//  override val tabs: StateFlow<ReviewToolwindowTabs<GCPRToolWindowTab, GCPRToolWindowTabViewModel>> = tabsHelper.tabs.asStateFlow()
//
//  private fun createVm(tab: GCPRToolWindowTab.PullRequest): GCPRToolWindowTabViewModel.PullRequest =
//    GCPRToolWindowTabViewModel.PullRequest(cs, this, tab.prId)
//
//  private fun createVm(tab: GCPRToolWindowTab.NewPullRequest): GCPRToolWindowTabViewModel.NewPullRequest =
//    GCPRToolWindowTabViewModel.NewPullRequest(project, dataContext)
//
//  override fun selectTab(tab: GCPRToolWindowTab?) = tabsHelper.select(tab)
//  override fun closeTab(tab: GCPRToolWindowTab) = tabsHelper.close(tab)
//
//  fun createPullRequest(requestFocus: Boolean = true) {
//    tabsHelper.showTab(GCPRToolWindowTab.NewPullRequest, ::createVm) {
//      if (requestFocus) {
//        requestFocus()
//      }
//    }
//  }
//
//  fun viewList(requestFocus: Boolean = true) {
//    selectTab(null)
//    if (requestFocus) {
//      listVm.requestFocus()
//    }
//  }
//
//  fun viewPullRequest(id: GCPRIdentifier, requestFocus: Boolean = true) {
//    if (requestFocus) {
//      twVm.activate()
//    }
//    tabsHelper.showTab(GCPRToolWindowTab.PullRequest(id), ::createVm) {
//      if (requestFocus) {
//        requestFocus()
//      }
//    }
//  }
//
//  fun viewPullRequest(id: GCPRIdentifier, commitOid: String) {
//    twVm.activate()
//    tabsHelper.showTab(GCPRToolWindowTab.PullRequest(id), ::createVm) {
//      selectCommit(commitOid)
//    }
//  }
//
//  fun openPullRequestTimeline(id: GCPRIdentifier, requestFocus: Boolean) =
//    dataContext.filesManager.createAndOpenTimelineFile(id, requestFocus)
//
//  fun openPullRequestDiff(id: GCPRIdentifier, requestFocus: Boolean) =
//    dataContext.filesManager.createAndOpenDiffFile(id, requestFocus)
//
//  fun acquireInfoViewModel(id: GCPRIdentifier, disposable: Disposable): GCPRInfoViewModel =
//    pullRequestsVms[id].acquireValue(disposable).infoVm
//
//  fun acquireEditorReviewViewModel(id: GCPRIdentifier, disposable: Disposable): GCPRReviewInEditorViewModel =
//    pullRequestsVms[id].acquireValue(disposable).editorVm
//
//  fun acquireBranchWidgetModel(id: GCPRIdentifier, disposable: Disposable): GCPRBranchWidgetViewModel =
//    pullRequestsVms[id].acquireValue(disposable).branchWidgetVm
//
//  fun acquireDiffViewModel(id: GCPRIdentifier, disposable: Disposable): GCPRDiffViewModel =
//    pullRequestsVms[id].acquireValue(disposable).diffVm
//
//  fun acquireTimelineViewModel(id: GCPRIdentifier, disposable: Disposable): GCPRTimelineViewModel =
//    pullRequestsVms[id].acquireValue(disposable).timelineVm
//
//  fun findDetails(pullRequest: GCPRIdentifier): GCPullRequestShort? =
//    dataContext.listLoader.loadedData.find { it.id == pullRequest.id }
//    ?: dataContext.dataProviderRepository.findDataProvider(pullRequest)?.detailsData?.loadedDetails
//
//  private val prOnCurrentBranchRefreshSignal =
//    MutableSharedFlow<Unit>(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
//
//  val prOnCurrentBranch: StateFlow<ComputedResult<GCPRIdentifier?>?> =
//    repoManager.findHostedRemoteBranchTrackedByCurrent(connection.repo.gitRepository)
//      .combineTransform(prOnCurrentBranchRefreshSignal.withInitial(Unit)) { projectAndBranch, _ ->
//        if (projectAndBranch == null) {
//          emit(ComputedResult.success(null))
//        }
//        else {
//          val (targetProject, remoteBranch) = projectAndBranch
//          computeEmitting {
//            val targetRepository = targetProject.repository.repositoryPath
//            dataContext.creationService.findOpenPullRequest(null, targetRepository, remoteBranch)
//          }?.onFailure {
//            LOG.warn("Could not lookup a pull request for current branch", it)
//          }
//        }
//      }.stateIn(cs, SharingStarted.Lazily, null)
//
//  suspend fun isExistingPullRequest(pushResult: GitPushRepoResult): Boolean? {
//    val creationService = dataContext.creationService
//    val repositoryDataService = dataContext.repositoryDataService
//
//    val repositoryMapping = repositoryDataService.repositoryMapping
//    val defaultRemoteBranch = repositoryDataService.getDefaultRemoteBranch() ?: return null
//
//    val pullRequest = creationService.findOpenPullRequest(
//      baseBranch = defaultRemoteBranch,
//      repositoryMapping.repository.repositoryPath,
//      headBranch = GitStandardRemoteBranch(repositoryMapping.gitRemote, pushResult.sourceBranch)
//    )
//
//    return pullRequest != null
//  }
//
//  fun refreshPrOnCurrentBranch() {
//    prOnCurrentBranchRefreshSignal.tryEmit(Unit)
//  }
//}
